package com.rm.zeyou.pay.wxpay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rm.zeyou.constant.NumberConstants;
import com.rm.zeyou.entity.Technician;
import com.rm.zeyou.entity.UserItemOrder;
import com.rm.zeyou.entity.UserMemberOrder;
import com.rm.zeyou.exception.ErrorCodeException;
import com.rm.zeyou.exception.ErrorCodeExceptionEnum;
import com.rm.zeyou.mapper.TechnicianMapper;
import com.rm.zeyou.mapper.UserMemberOrderMapper;
import com.rm.zeyou.pay.wxpay.entity.GetAccessTokenByCodeBean;
import com.rm.zeyou.pay.wxpay.service.WeChatNotifyService;
import com.rm.zeyou.pay.wxpay.service.WechatH5LoginService;
import com.rm.zeyou.pay.wxpay.util.WxPayUtil;
import com.rm.zeyou.pay.wxpay.vo.WxPayAsyncDecryptVO;
import com.rm.zeyou.pay.wxpay.vo.WxPayAsyncReturnVo;
import com.rm.zeyou.pay.wxpay.vo.WxPayAsyncVO;
import com.rm.zeyou.pay.wxpay.wxenum.WxAsyncResponseEnum;
import com.rm.zeyou.service.UserItemOrderService;
import com.rm.zeyou.util.check.CheckEmptyUtil;
import com.rm.zeyou.util.http.HttpUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.GeneralSecurityException;


/**
 * 微信支付服务类（只实现V3接口）
 *
 * @author zhangkechen
 * @since 2022/9/13 17:32
 */
@Service
@Log4j2
@Transactional(rollbackFor = RuntimeException.class)
public class WeChatNotifyServiceImpl implements WeChatNotifyService {

    @Resource
    private WxPayUtil wxPayUtil;
    @Resource
    private WechatH5LoginService wechatH5LoginService;
    @Resource
    private UserItemOrderService userItemOrderService;
    @Resource
    private UserMemberOrderMapper userMemberOrderMapper;
    @Resource
    private TechnicianMapper technicianMapper;


    /**
     * 常规服务订单回掉
     *
     * @param request
     * @param response
     * @return
     * @throws IOException
     * @throws GeneralSecurityException
     */
    @Override
    public WxPayAsyncReturnVo notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.info("微信支付 常规服务订单回掉");
        // 处理通知参数
        String body = HttpUtil.readData(request);
        WxPayAsyncVO wxPayAsyncVo = JSONObject.parseObject(body, WxPayAsyncVO.class);
        boolean b = wxPayUtil.verifySign(request, body);
        if (b) {
            log.info("通知验签成功");
        } else {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.VERIFY_ERROR);
        }
        // 解密
        String decryptedString = wxPayUtil.decryptToString(wxPayAsyncVo.getResource().getAssociated_data(), wxPayAsyncVo.getResource().getNonce(), wxPayAsyncVo.getResource().getCiphertext());
        log.info("微信支付回调 - 解密: {}", decryptedString);
        log.info("解密报文：{}", decryptedString);
        // 序列化
        WxPayAsyncDecryptVO wxPayAsyncDecryptRequestVo = JSONObject.parseObject(decryptedString, WxPayAsyncDecryptVO.class);
        log.info("将解密报文转换成map：{}", wxPayAsyncDecryptRequestVo);
        /**
         * TODO 处理业务
         */
        String orderNo = wxPayAsyncDecryptRequestVo.getOutTradeNo();
        log.info("订单编号:{}", orderNo);
        Integer payerTotal = wxPayAsyncDecryptRequestVo.getAmount().getPayerTotal();
        log.info("支付金额:{}", payerTotal);
        BigDecimal payPrice = new BigDecimal(payerTotal).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        UserItemOrder userItemOrder = userItemOrderService.getOne(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getOrderNo, orderNo));
        if (payPrice.compareTo(userItemOrder.getNeedPayPrice()) != 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAY_PRICE_ERROR);
        }
        userItemOrderService.updateOrder(userItemOrder.getOrderNo(), userItemOrder.getPayType());


        // 应答微信
        return new WxPayAsyncReturnVo(WxAsyncResponseEnum.WX_PAY_ASYNC_RESPONSE_SUCCESS);
    }

    @Override
    public String wechatNotify(HttpServletRequest request, HttpServletResponse response) {
        String code = request.getParameter("code");
        String errcode = request.getParameter("errcode");
        String state = request.getParameter("state");
        if (CheckEmptyUtil.isEmpty(code)) {//返回的code为空
            log.info("code为空");
        }

        log.info("code:{}", code);
        log.info("errcode:{}", errcode);
        log.info("tid:{}", state);

        Technician technician = technicianMapper.selectById(state);

        GetAccessTokenByCodeBean accessToken = wechatH5LoginService.getAccessToken(code);
        log.info("accessToken:[{}]", accessToken);

        technician.setH5OpenId(accessToken.getOpenid());
        technicianMapper.updateById(technician);

        // 设置响应内容类型为HTML
        response.setContentType("text/html;charset=UTF-8");
        return "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "<meta charset=\"utf-8\">\n" +
                "<title></title>\n" +
                "</head>\n" +
                "<script type=\"text/javascript\">\n" +
                "\tfunction toPage(){\n" +
                "\t\tconsole.log(1111)\n" +
                // todo 设置页面回调
                "\t\twindow.location.href='https://www.zeyouinlife.com:8000/#/pages/index/index'\n" +
                "\t}\n" +
                "\ttoPage()\n" +
                "\t\n" +
                "</script>\n" +
                "<body>\n" +
                "\t<!-- <meta charset=\"utf-8\" http-equiv=\"refresh\" content=\"1;https://www.zeyouinlife.com:8000/#\">  -->\n" +
                "</body>\n" +
                "</html>";
    }

    @Override
    public WxPayAsyncReturnVo rechargeNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("微信支付 开通会员回调");
        // 处理通知参数
        String body = HttpUtil.readData(request);
        WxPayAsyncVO wxPayAsyncVo = JSONObject.parseObject(body, WxPayAsyncVO.class);
        boolean b = wxPayUtil.verifySign(request, body);
        if (b) {
            log.info("通知验签成功");
        } else {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.VERIFY_ERROR);
        }
        // 解密
        String decryptedString = wxPayUtil.decryptToString(wxPayAsyncVo.getResource().getAssociated_data(), wxPayAsyncVo.getResource().getNonce(), wxPayAsyncVo.getResource().getCiphertext());
        log.info("微信支付回调 - 解密: {}", decryptedString);
        log.info("解密报文：{}", decryptedString);
        // 序列化
        WxPayAsyncDecryptVO wxPayAsyncDecryptRequestVo = JSONObject.parseObject(decryptedString, WxPayAsyncDecryptVO.class);
        log.info("将解密报文转换成map：{}", wxPayAsyncDecryptRequestVo);
        /**
         * TODO 处理业务
         */
        String orderNo = wxPayAsyncDecryptRequestVo.getOutTradeNo();
        log.info("订单编号:{}", orderNo);
        //单位：分
        Integer payerTotal = wxPayAsyncDecryptRequestVo.getAmount().getPayerTotal();
        //单位：元
        BigDecimal yuan = new BigDecimal(payerTotal).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        log.info("支付金额:{}", payerTotal);
        UserMemberOrder userMemberOrder = userMemberOrderMapper.selectOne(new LambdaQueryWrapper<UserMemberOrder>().eq(UserMemberOrder::getRechangeOrderNo, orderNo));
        if (CheckEmptyUtil.isEmpty(userMemberOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (yuan.compareTo(userMemberOrder.getPayPrice()) != 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAY_PRICE_ERROR);
        }

        //修改订单支付状态
        userMemberOrder.setPayStatus(NumberConstants.ONE_CONSTANTS);
        userMemberOrderMapper.updateById(userMemberOrder);
        userItemOrderService.payVip(userMemberOrder.getUserId(), userMemberOrder.getMemberType(), userMemberOrder.getEffectDay());

        // 应答微信
        return new WxPayAsyncReturnVo(WxAsyncResponseEnum.WX_PAY_ASYNC_RESPONSE_SUCCESS);
    }

    @Override
    public WxPayAsyncReturnVo upgradeNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("微信支付 升级服务订单回掉");
        // 处理通知参数
        String body = HttpUtil.readData(request);
        WxPayAsyncVO wxPayAsyncVo = JSONObject.parseObject(body, WxPayAsyncVO.class);
        boolean b = wxPayUtil.verifySign(request, body);
        if (b) {
            log.info("通知验签成功");
        } else {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.VERIFY_ERROR);
        }
        // 解密
        String decryptedString = wxPayUtil.decryptToString(wxPayAsyncVo.getResource().getAssociated_data(), wxPayAsyncVo.getResource().getNonce(), wxPayAsyncVo.getResource().getCiphertext());
        log.info("微信支付回调 - 解密: {}", decryptedString);
        log.info("解密报文：{}", decryptedString);
        // 序列化
        WxPayAsyncDecryptVO wxPayAsyncDecryptRequestVo = JSONObject.parseObject(decryptedString, WxPayAsyncDecryptVO.class);
        log.info("将解密报文转换成map：{}", wxPayAsyncDecryptRequestVo);
        /**
         * TODO 处理业务
         */
        String orderNo = wxPayAsyncDecryptRequestVo.getOutTradeNo();
        log.info("订单编号:{}", orderNo);
        Integer payerTotal = wxPayAsyncDecryptRequestVo.getAmount().getPayerTotal();
        log.info("支付金额:{}", payerTotal);
        BigDecimal payPrice = new BigDecimal(payerTotal).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        UserItemOrder userItemOrder = userItemOrderService.getOne(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getOrderNo, orderNo));
        if (payPrice.compareTo(userItemOrder.getNeedPayPrice()) != 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAY_PRICE_ERROR);
        }
        userItemOrderService.upgradeUpdateOrder(userItemOrder.getOrderNo(), userItemOrder.getPayType());


        // 应答微信
        return new WxPayAsyncReturnVo(WxAsyncResponseEnum.WX_PAY_ASYNC_RESPONSE_SUCCESS);
    }

    @Override
    public WxPayAsyncReturnVo bellNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("微信支付 加钟服务订单回掉");
        // 处理通知参数
        String body = HttpUtil.readData(request);
        WxPayAsyncVO wxPayAsyncVo = JSONObject.parseObject(body, WxPayAsyncVO.class);
        boolean b = wxPayUtil.verifySign(request, body);
        if (b) {
            log.info("通知验签成功");
        } else {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.VERIFY_ERROR);
        }
        // 解密
        String decryptedString = wxPayUtil.decryptToString(wxPayAsyncVo.getResource().getAssociated_data(), wxPayAsyncVo.getResource().getNonce(), wxPayAsyncVo.getResource().getCiphertext());
        log.info("微信支付回调 - 解密: {}", decryptedString);
        log.info("解密报文：{}", decryptedString);
        // 序列化
        WxPayAsyncDecryptVO wxPayAsyncDecryptRequestVo = JSONObject.parseObject(decryptedString, WxPayAsyncDecryptVO.class);
        log.info("将解密报文转换成map：{}", wxPayAsyncDecryptRequestVo);
        /**
         * TODO 处理业务
         */
        String orderNo = wxPayAsyncDecryptRequestVo.getOutTradeNo();
        log.info("订单编号:{}", orderNo);
        Integer payerTotal = wxPayAsyncDecryptRequestVo.getAmount().getPayerTotal();
        log.info("支付金额:{}", payerTotal);
        BigDecimal payPrice = new BigDecimal(payerTotal).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        UserItemOrder userItemOrder = userItemOrderService.getOne(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getOrderNo, orderNo));
        if (payPrice.compareTo(userItemOrder.getNeedPayPrice()) != 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAY_PRICE_ERROR);
        }
        userItemOrderService.bellUpdateOrder(userItemOrder.getOrderNo(), userItemOrder.getPayType());


        // 应答微信
        return new WxPayAsyncReturnVo(WxAsyncResponseEnum.WX_PAY_ASYNC_RESPONSE_SUCCESS);
    }


}
